/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "key_task.h"
#include "led_task.h"
#include "ec_bsp_aht21_driver.h"
#include "iic_hal.h"
#include "elog.h"
#include "ec_bsp_temp_humi_xxx_handler.h"
#include "queue.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define AHT_CLK_ENABLE __HAL_RCC_GPIOB_CLK_ENABLE()
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
iic_bus_t  iic_bus_instance = {
    .IIC_SDA_PORT = GPIOB,
    .IIC_SDA_PIN = GPIO_PIN_13,
    .IIC_SCL_PORT = GPIOB,
    .IIC_SCL_PIN = GPIO_PIN_14
};
/* USER CODE END Variables */
/* Definitions for KeyTask */
osThreadId_t KeyTaskHandle;
const osThreadAttr_t KeyTask_attributes = {
  .name = "KeyTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};
/* Definitions for appTask */
osThreadId_t appTaskHandle;
const osThreadAttr_t appTask_attributes = {
  .name = "appTask",
  .stack_size = 256 * 4,
  .priority = (osPriority_t) osPriorityLow,
};
/* Definitions for tempHumiTask */
osThreadId_t tempHumiTaskHandle;
const osThreadAttr_t tempHumiTask_attributes = {
  .name = "tempHumiTask",
  .stack_size = 256 * 4,
  .priority = (osPriority_t) osPriorityLow,
};

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
aht21_status_t iic_init_myown(void * bus)
{
    AHT_CLK_ENABLE;
    IICInit(&iic_bus_instance);
    return AHT21_OK;
}

aht21_status_t iic_start_myown(void * bus)
{
    IICStart(&iic_bus_instance);
    return AHT21_OK;
}

aht21_status_t iic_stop_myown(void * bus)
{
    IICStop(&iic_bus_instance);
    return AHT21_OK;
}

aht21_status_t iic_wait_ack_mywon(void * bus)
{
    unsigned char ret = SUCCESS;
    ret = IICWaitAck(&iic_bus_instance); 
    if (SUCCESS == ret)
    {
        return AHT21_OK;
    }
    else
    {
        return AHT21_ERRORTIMEOUT;
    }
}

aht21_status_t iic_send_ack_own(void * bus)
{
    IICSendAck(&iic_bus_instance);
    return AHT21_OK;
}

aht21_status_t iic_send_no_ack_own(void * bus)
{
    IICSendNotAck(&iic_bus_instance);
    return AHT21_OK;
}

aht21_status_t iic_send_byte_own(void * bus, const uint8_t data)
{
    IICSendByte(&iic_bus_instance, data);
    return AHT21_OK;
}

aht21_status_t iic_receive_byte_own(void * bus, uint8_t * const data)
{
    *data = IICReceiveByte(&iic_bus_instance);
    return AHT21_OK;
}

temp_humi_status_t os_queue_create_own(uint32_t const item_num,
                                       uint32_t const item_size, 
                                       void ** const queue_handle)
{
    *queue_handle = xQueueCreate( item_num, item_size );
    log_e("queu handle addr: %p", *queue_handle);
    if( *queue_handle == NULL) {
        return TEMP_HUMI_ERRORPARAMETER;
    } else {
        return TEMP_HUMI_OK;
    }
}

temp_humi_status_t os_queue_put_own(void * const queue_handle,
                                    void * const item, 
                                    uint32_t timeout)
{
    if (pdTRUE == xQueueSend( queue_handle, item, timeout )) {
        return TEMP_HUMI_OK;
    } else {
        return TEMP_HUMI_ERROR;
    }
}

temp_humi_status_t os_queue_get_own(void * queue_handle,
                                     void *msg, uint32_t timeout)
{
    if (pdTRUE == xQueueReceive( queue_handle, msg, timeout )) {
        return TEMP_HUMI_OK;
    } else {
        return TEMP_HUMI_ERROR;
    }
}

void temp_humi_callback(float *temperature, float *humidity)
{
    log_d("callback: temperature = %f, humidity = %f", *temperature, *humidity);
}
/* USER CODE END FunctionPrototypes */

void StartKeyTask(void *argument);
void appTaskFunction(void *argument);
void temp_humi_handler_thread(void *argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */
static iic_driver_interface_t iic_driver_interface = {
    .pf_iic_init                = iic_init_myown,
    .pf_iic_start               = iic_start_myown,
    .pf_iic_stop                = iic_stop_myown,
    .pf_iic_wait_ack            = iic_wait_ack_mywon,
    .pf_iic_send_ack            = iic_send_ack_own,
    .pf_iic_send_no_ack         = iic_send_no_ack_own,
    .pf_iic_send_byte           = iic_send_byte_own,
    .pf_iic_receive_byte        = iic_receive_byte_own,
    .pf_critical_enter          = (aht21_status_t (*)(void))vPortEnterCritical,
    .pf_critical_exit           = (aht21_status_t (*)(void))vPortExitCritical
};

static timebase_interface_t timebase_interface = {
    .pfget_tick_count = HAL_GetTick
};

static yield_interface_t yield_interface = {
    .pf_rtos_yield = vTaskDelay
};

static temp_humi_handler_os_interface_t os_interface = {
    .os_delay_ms        = vTaskDelay,
    .os_queue_create    = os_queue_create_own,
    .os_queue_put       = os_queue_put_own,
    .os_queue_get       =os_queue_get_own
};

static temp_humi_handler_all_input_arg_t input_arg = {
    .iic_driver_interface   = &iic_driver_interface,
    .timebase_interface     = &timebase_interface,
    .os_interface           = &os_interface,
    .yield_interface        = &yield_interface
};
  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* creation of KeyTask */
  KeyTaskHandle = osThreadNew(StartKeyTask, NULL, &KeyTask_attributes);

  /* creation of appTask */
  appTaskHandle = osThreadNew(appTaskFunction, NULL, &appTask_attributes);

  /* creation of tempHumiTask */
  tempHumiTaskHandle = osThreadNew(temp_humi_handler_thread, (void*)&input_arg, &tempHumiTask_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_EVENTS */
  /* add events, ... */
  /* USER CODE END RTOS_EVENTS */

}

/* USER CODE BEGIN Header_StartKeyTask */
/**
  * @brief  Function implementing the KeyTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartKeyTask */
void StartKeyTask(void *argument)
{
  /* USER CODE BEGIN StartKeyTask */
  key_interface.pfinit();
  /* Infinite loop */
  for(;;)
  {
    key_interface.pftask();
    osDelay(1);
  }
  /* USER CODE END StartKeyTask */
}

/* USER CODE BEGIN Header_appTaskFunction */
/**
* @brief Function implementing the appTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_appTaskFunction */
void appTaskFunction(void *argument)
{
  /* USER CODE BEGIN appTaskFunction */
  temp_humi_xxx_event_t event = {
    .lifetime = 2000,
    .type = TEMP_HUMI_EVENT_BOTH,
    .pfcallback = temp_humi_callback
  };
  log_d("App task start");
  /* Infinite loop */
  for(;;)
  {
    bsp_temp_humi_xxx_read(&event);
    osDelay(1000);
  }
  /* USER CODE END appTaskFunction */
}

/* USER CODE BEGIN Header_temp_humi_handler_thread */
/**
* @brief Function implementing the tempHumiTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_temp_humi_handler_thread */
__weak void temp_humi_handler_thread(void *argument)
{
  /* USER CODE BEGIN temp_humi_handler_thread */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END temp_humi_handler_thread */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/* USER CODE END Application */

